# -*- coding: utf-8 -*-
'''
@author: atuo.cn
'''
import re
from epubbuilder import ez_epub

class ContentSection(ez_epub.Section):

    def __init__(self):
        super().__init__()
        self.lineNo = -1
        self.rawBufferSize=5
        self.rawText=[]
        self.rawTitleIndex=0
    @property
    def rawTitle(self):
        return self.rawText[self.rawTitleIndex] if self.rawText else ""


class MetaSection(ContentSection):

    def __init__(self):
        super().__init__()
        self.rawBufferSize=5

ALL_HINTS={
    "MaxSectionTitleLen":35,
    "IgnoreEmptySection":True,
    "FilterKeywords":["集团","部门","回合"],
    "Prefix":["正文","VIP章节目录"]
}

class SectionRules:
    
    def __init__(self, hints):
        self.title = None
        self.titlestart = -1
        self.lastmatch=None

        try:
            maxTitleLen=int(hints["MaxSectionTitleLen"])
        except:
            maxTitleLen=ALL_HINTS["MaxSectionTitleLen"]
        self.maxtitlelen=maxTitleLen
        self.rules =[
            self.matchpattern,
            lambda m: len(m.string) <= maxTitleLen,
        ]
        if "FilterKeywords" in hints and hints["FilterKeywords"]:
            rule=SectionRules.FilterKeywords(self,hints["FilterKeywords"])
            self.rules.append(rule)        
        if "Prefix" in hints and hints["Prefix"]:
            rule=SectionRules.Prefix(self,hints["Prefix"])
            self.rules.append(rule)        
        if "IgnoreEmptySection" in hints and hints["IgnoreEmptySection"]:
            self.rules.append(self.ignoreEmptySection)        
            
    def matchpattern(self, match):
        if match is not None and match.start()>=0:
            self.titlestart=match.start()
            self.title=match.string[self.titlestart:]
            return True
        else:
            self.title=None
            self.titlestart=-1
            return False
        
    def ignoreEmptySection(self,match):
        return (not self.lastmatch) and match
        
    class FilterKeywords:
        PATTERN=re.compile(r"[0-9零○一二两三四五六七八九十百千廿卅卌壹贰叁肆伍陆柒捌玖拾佰仟万１２３４５６７８９０]+(\w+)",re.I)
        def __init__(self, sectionrules, keywords):
            self.sectionrules=sectionrules
            self.keywords=keywords
        def __call__(self, match):
            title=self.sectionrules.title
            it=SectionRules.FilterKeywords.PATTERN.finditer(title)
            #parameter m is a match object.
            testwords=lambda m: any(map(lambda w: m.group(1).startswith(w),self.keywords))
            return not any(map(testwords,it))
    
    class Prefix:
        def __init__(self,sectionrules,prefixies):
            self.sectionrules=sectionrules
            self.prefixies=prefixies
        def __call__(self,match):
            s=match.string[:self.sectionrules.titlestart].rstrip().upper()
            if s:
                return any(map(lambda p: p==s, self.prefixies))
            else:
                return True
    
    #run section rules, 
    #and use "title" attribute to get the result of section title. 
    def test(self, pattern, line):
        match= pattern.search(line,0,self.maxtitlelen)
        result= all(map(lambda rule: rule(match),self.rules))
        self.lastmatch = match if result else None
        return result
    

class TextBook:
    
    def __init__(self):
        self.bookTitle = ''
        self.authors = []
        self.lang = "zh-CN"
        self.cover = ""
        self.maincss = ""

        self.file = ""
        self.encoding = "gb18030"
        self.contentRange =(0,-1)
        self.sectionRe = ""
        
        self.captureBookTitle = False
        self.bookTitleRe=""
        self.captureAuthor = False
        self.authorRe=""
        self.dropHtml = False
        self._dropHtmlRe=None
        
        self.metasection = None
        self.includemeta = True

        self.hints = {}
    
    @property
    def dropHtmlRe(self):
        return self._dropHtmlRe.pattern
    @dropHtmlRe.setter
    def dropHtmlRe(self, value):
        if isinstance(value,type(re.compile(""))):
            self._dropHtmlPattern=value
        else:
            self._dropHtmlPattern=re.compile(value,re.I)
    
    def formatParagraph(self, paragraph):
        if self.dropHtml:
            paragraph=self._dropHtmlPattern.sub("", paragraph)
        return paragraph
    
    def parseMeta(self,line):
        if self.captureBookTitle:
            m=re.match(self.bookTitleRe,line)
            if m:
                self.bookTitle=m.group(1 if m.lastindex else 0)
        
        if self.captureAuthor:
            m=re.match(self.authorRe,line)
            if m:
                authors=m.group(1 if m.lastindex else 0)
                self.authors=re.split(",;，；",authors)
        
    def getline(self):
        startLineNum = self.contentRange[0]
        endLineNum = self.contentRange[1]
        #endLineNum < 0 means end of the file
        if (endLineNum>0 and endLineNum<startLineNum) or startLineNum <0:
            return

        lastLine=None
        with open(self.file, encoding=self.encoding) as fin:
            for lineNum, line in enumerate(fin, start=startLineNum):
                line = line.strip()
                if line: 
                    yield (lineNum, line, lastLine)
                    lastLine=line
                
                if endLineNum > 0 and lineNum >= endLineNum:
                    break
                
    def createSection(self, sctiontype, title, lineNum, lastLine):
        section = sctiontype()
        section.css = 'p {text-indent: 2em;}'
        section.title = title
        section.lineNo=lineNum + 1
        if lastLine:
            section.rawText.append(lastLine)
            section.rawTitleIndex=1
        else:
            section.rawTitleIndex=0
            
        return section
    
    def parseBook(self):
        self.sections = []
        pattern = re.compile(self.sectionRe)
        section = None
        rules = SectionRules(self.hints)
        bufferlen=metalines=0
        
        for lineNum, line, lastLine in self.getline():
            if rules.test(pattern, line):
                section=self.createSection(ContentSection,rules.title,lineNum,lastLine)
                self.sections.append(section)
                bufferlen=section.rawBufferSize-section.rawTitleIndex
            else:
                if not section:
                    section = self.createSection(MetaSection, "前言", lineNum,lastLine)
                    self.metasection = section
                    if self.includemeta: self.sections.append(section)
                    bufferlen=section.rawBufferSize-section.rawTitleIndex
                    metalines=5
                    
                section.text.append(self.formatParagraph(line))

            if bufferlen>0:
                section.rawText.append(line)
                bufferlen-=1

            if metalines > 0:
                self.parseMeta(line)
                metalines-=1

    def make(self, render, destPath):
        render.render(self, destPath)        
        